<template>
  <div class="edit-dept-root">
    <!-- 编辑部门的弹层 -->
    <!-- 
      @update:visible="$emit('update:showDialog', $event)"
      @closed="onCancel"
    -->
    <el-dialog
      :title="_.get(treeNode, 'name') + ' · 编辑部门'"
      :visible="showDialog"
      @close="onCancel"
    >
      <div ref="formBox" v-loading="loading">
        <!-- 表单组件  el-form   label-width设置label的宽度   -->
        <!-- 匿名插槽 -->
        <el-form
          label-width="120px"
          :model="formData"
          :rules="rules"
          ref="form"
        >
          <el-form-item label="部门名称" prop="name">
            <el-input
              style="width: 80%"
              placeholder="1-50个字符"
              v-model="formData.name"
              ref="name"
            />
          </el-form-item>
          <el-form-item label="部门编码" prop="code">
            <el-input
              style="width: 80%"
              placeholder="1-50个字符"
              v-model="formData.code"
              ref="code"
            />
          </el-form-item>
          <el-form-item label="部门负责人" prop="manager">
            <!-- clearable：加上后，允许清空，右侧会出现 x 按钮 -->

            <!-- 
          // 我们能手动监听 el-select 的 blur 事件
          // 监听后，可以在事件处理函数中，手动触发校验指定的表单项（部门负责人）
          // 问题就是：如何手动触发？只能抱希望给 elementui 组件库的 el-form
          // 巧了，el-form 还真有，validateField('manager')
          // 当触发 blur 事件的时候（点击某一项），此时 blur 的事件回调函数已经触发了（验证这一项表单数据），但是点击的那一项值，还没有设置到 el-select v-model="formData.manager" 上（manger的值还是空）
         -->
            <!-- @blur="onBlurOfEmployeeSelect" -->

            <!-- visible-change 下拉框出现/隐藏时触发 -->
            <el-select
              ref="select"
              style="width: 80%"
              placeholder="请选择"
              v-model="formData.manager"
              @focus="getEmployeeSimple"
              @visible-change="visibleChange"
            >
              <!-- label：显示的内容 -->
              <!-- value：选中的值 -->
              <!-- 实际开发中，:value="唯一标识" -->
              <el-option
                v-for="v of employees"
                :key="v.id"
                :label="v.username"
                :value="v.username"
              />
            </el-select>
          </el-form-item>
          <el-form-item label="部门介绍" prop="introduce">
            <el-input
              style="width: 80%"
              placeholder="1-300个字符"
              v-model="formData.introduce"
              type="textarea"
              :rows="3"
            />
          </el-form-item>
        </el-form>
        <!-- el-dialog 有专门放置底部操作栏的 插槽 具名插槽 -->
        <!-- 但是，这里不用，为了整理显示 v-loading，把 header 和 body 全部放到一个 div 里面去 -->
        <!-- 因为用请求拦截器中的 loadingOptions，显示时机晚了，因为在真正发送添加部门请求前，会先进行表单校验，表单校验规则中也有发请求 -->
        <!-- <template #footer> -->
        <div style="display: flex; justify-content: center; gap: 20px">
          <el-button type="primary" size="small" @click="onOk">确定</el-button>
          <el-button size="small" @click="onCancel">取消</el-button>
        </div>
        <!-- </template> -->
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { getDepartments, getDepartDetail } from '@/api/departments';
import { getEmployeeSimple } from '@/api/employees';
export default {
  name: 'EditDept',
  props: {
    treeNode: {
      type: Object,
    },
    showDialog: {
      type: Boolean,
      default: false,
    },
  },
  data() {
    return {
      loading: false, // 是否正在加载中
      employees: [], // 负责人列表
      // 定义表单数据
      formData: {
        name: '', // 部门名称
        code: '', // 部门编码
        manager: '', // 部门管理者
        introduce: '', // 部门介绍
      },
      // 定义校验规则
      rules: {
        name: [
          { required: true, message: '部门名称不能为空', trigger: 'blur' },
          {
            min: 1,
            max: 50,
            message: '部门名称要求1-50个字符',
            trigger: 'blur',
          },
          {
            validator: async (rule, value, cb) => {
              const { depts } = await getDepartments({
                target: this.$refs.name.$el,
                customClass: 'my-loading',
              });
              const isRepeat = depts.some(
                v => v.pid === this.treeNode.id && v.name === value
              );
              if (isRepeat) {
                cb(
                  new Error(`"${this.treeNode.name}" 下已经存在 "${value}" 了`)
                );
              } else {
                cb();
              }
            },
            trigger: 'blur',
          },
        ],
        code: [
          { required: true, message: '部门编码不能为空', trigger: 'blur' },
          {
            min: 1,
            max: 50,
            message: '部门编码要求1-50个字符',
            trigger: 'blur',
          },
          {
            validator: async (rule, value, cb) => {
              const { depts } = await getDepartments({
                target: this.$refs.code.$el,
                customClass: 'my-loading',
              });

              // const isRepeat = depts.some(v => v.code === value)

              // 在数组中找匹配条件的元素，并返回，如果没找到，返回 null
              const existDept = depts.find(v => v.code === value);
              // 如果有存在的部门
              if (existDept) {
                cb(
                  new Error(
                    `组织架构下已经存在 "${existDept.name} · ${value}" 编码了`
                  )
                );
              } else {
                cb();
              }
            },
            trigger: 'blur',
          },
        ],
        manager: [
          {
            required: true,
            message: '部门负责人不能为空',
            trigger: 'blur',
          },
        ],
        introduce: [
          { required: true, message: '部门介绍不能为空', trigger: 'blur' },
          {
            trigger: 'blur',
            min: 1,
            max: 300,
            message: '部门介绍要求1-50个字符',
          },
        ],
      },
    };
  },

  watch: {
    // 当 显示 对话框时 就去 获取部门详情 回显表单数据
    showDialog: async function (isShow) {
      console.log('[ isShow ]-199', isShow);
      if (isShow) {
        this.formData = await getDepartDetail(this.treeNode.id, {
          target: this.$refs.formBox,
        });
      }
    },
  },

  // created 只会执行一次，后续显示隐藏弹层时，就不会执行了，所以 获取详情回显 放在这里 不合适
  // async created() {
  //   // props 已经是最新的了， this 也能用了，  data 也有的， 只不过没有渲染视图
  //   if (this.treeNode?.id) {
  //     this.formData = await getDepartDetail(this.treeNode.id);
  //   }
  // },

  // updated 每次重新渲染完成后 都会执行，又因为，只要数据（props、data）发生变化，就会驱动视图重新渲染，所以 当修改表单数据时 也会触发 updated，所以 获取详情回显 放在这里 也不合适
  // updated() {
  //   console.log('updated');
  // },

  methods: {
    onCancel() {
      console.log('[ onCancel ]-226');
      this.$emit('update:showDialog', false);
      // resetFields 有两个功能：1. 重置表单数据   2. 清空错误校验
      this.$refs.form.resetFields(); // 关闭弹层时，重置表单，防止再次打开时，还有上一次的错误提示
    },
    async onOk() {
      try {
        // 这里为什么不用统一封装好的 loadingOptions 去转圈圈呢？
        // 因为在请求发出去前，需要对整个表单进行校验，而对部门名称和部门编码的校验规则中，又包含了请求
        // 所以等部门名称和部门编码校验完再转圈圈 时机晚了，故 使用 v-loading 提前显示转圈圈
        this.loading = true;
        await this.$refs.form.validate();
        // await addDepartment({ ...this.formData, pid: this.treeNode.id });
        this.$emit('edit');
        this.$emit('update:showDialog', false);
        this.$refs.form.resetFields(); // 提交成功，重置表单
      } finally {
        this.loading = false; // 不管是否成功，都关闭转圈圈
      }
    },
    // 下拉框出现/隐藏时触发
    visibleChange(isShow) {
      // isShow： true，显示，   false: 隐藏
      console.log('visibleChange', isShow);
      if (!isShow) {
        this.$refs.form.validateField('manager');
      }
    },
    async getEmployeeSimple() {
      this.employees = await getEmployeeSimple({
        target: this.$refs.select.$el,
        customClass: 'my-loading',
      });
    },
  },
};
</script>

<style lang="scss" scoped>
.edit-dept-root {
  ::v-deep .my-loading {
    .el-loading-spinner {
      text-align: right;
      margin-top: -14px;

      svg {
        height: 30px;
        width: 30px;
        margin-right: -40px;
      }
    }
  }
}
</style>
